<template>
  <div class="ps-r report-container">
    <div class="mr-center report">
      <div
        v-for="(row, rowIndex) in dragReportData.children"
        :key="rowIndex"
        class="ps-r flex flex-center flex-nowrap layout-row"
        :style="rowStyle(row)"
        @drop="handleDropRow($event, row)"
        @dragover="handleDragOver($event, row)"
      >
        <transition name="slide-fade">
          <div
            draggable="true"
            class="flex flex-center cur-all w100 ps-a border-r5 row-controller-bar"
            @dragstart="handleDragRow($event, row)"
          >
            <div class="bar-btn-box">
              <span
                class="align-type-item cur-p"
                style="margin:0"
                @click="handleEditRow($event, row)"
              >
                <i class="el-icon-setting" />
              </span>
              <span
                class="align-type-item cur-p"
                style="margin:0 7px 0 0"
                @click="handleRemoveRow($event, row)"
              >
                <i class="el-icon-delete" />
              </span>
            </div>
          </div>
        </transition>
        <div
          v-for="(col, colIndex) in row.children"
          :key="colIndex"
          class="flex flex-center ps-r border-r5 layout-col-box"
          :class="{'cur-all': !!col.code}"
          :style="previewColStyle({width: col.initCol, height: row.initHeight, baseHeight: 1})"
          :draggable="col.code ? true : false"
          @mouseenter="col.code ? col.showChildrenControllerBar = true : null"
          @mouseleave="col.showChildrenControllerBar = false"
          @dragstart="handleDragCol($event, col)"
          @drop="handleDropCol($event, col)"
          @dragover="handleDragOver($event, col)"
        >
          <transition name="slide-fade">
            <div style="flex:1">
              <div
                v-show="col.code ? true : false"
                class="ps-a border-r5 w100 t0 flex flex-center col-controller-bar"
              >
                <span v-if="!col.showEditTitle">{{ col.name }}</span>
                <el-input v-else v-model="col.name" size="mini" style="width:200px;height:28px;" />
                <div>
                  <span class="bar-title-box cur-p" style="margin: 0;">
                    <i class="el-icon-edit" @click="showEditDialog(col)" />
                  </span>
                  <span class="bar-title-box cur-p" style="margin: 0;">
                    <i class="el-icon-setting" @click="showSettingDialog(col)" />
                  </span>
                  <span
                    class="bar-title-box cur-p"
                    style="margin: 0 5px 0 0"
                    @click="resetCol(col)"
                  >
                    <i class="el-icon-delete" />
                  </span>
                </div>
              </div>
              <div
                class="ps-a w100 flex flex-start"
                :style="previewColStyle({width: 24, height: row.initHeight - 30, baseHeight: 1}, {top: '30px', overflow:'auto'})"
              >
                <component
                  :is="col.code"
                  :key="colIndex"
                  :dialog-visible.sync="col.dialogVisible"
                  :config="col.paramList"
                />
              </div>
            </div>
          </transition>
        </div>
      </div>
    </div>

    <i
      v-show="!addRow.show"
      class="cur-p ps-a t0 ps-icon-btn el-icon-circle-plus-outline add-row-icon"
      title="布局设置"
      :style="floatBox"
      @click="addRow.show = true"
    />

    <i
      v-show="!addCol.show"
      class="cur-p ps-a t0 ps-icon-btn el-icon-circle-plus-outline add-col-icon"
      title="组件设置"
      :style="floatBox"
      @click="addCol.show = true"
    />

    <transition name="slide-fade">
      <div
        v-show="addRow.show"
        class="flex flex-center ps-a t0 l0 drag-report-add-box"
        :style="floatBox"
        @mouseenter="addRow.showControllerBar = true"
        @mouseleave="addRow.showControllerBar = false"
      >
        <transition name="slide-fade">
          <div
            class="w100 text-r title-box"
            style="height:40px;line-height:40px;font-size:18px;background:#545c64;color:#fff;"
          >
            <span style="float:left;padding-left:10px;">布局设置</span>
            <i class="cur-p el-icon-close" style="margin-right:20px;" @click="addRow.show = false" />
          </div>
        </transition>

        <default-layout-editor
          v-clickoutside="handleClickoutside(addRow)"
          @drag-row-start="handleDragNewRow"
        />
      </div>
    </transition>

    <transition name="slide-fade">
      <div
        v-show="addCol.show"
        class="flex flex-center ps-a t0 r0 drag-report-add-box drag-report-col-box"
        :style="floatBox"
        @mouseenter="addCol.showControllerBar = true"
        @mouseleave="addCol.showControllerBar = false"
      >
        <transition name="slide-fade">
          <div
            class="w100 text-r title-box"
            style="height:40px;line-height:40px;font-size:18px;background:#545c64;color:#fff;"
          >
            <span style="float:left;padding-left:10px;">组件清单</span>
            <i class="cur-p el-icon-close" style="margin-right:20px;" @click="addCol.show = false" />
          </div>
        </transition>

        <default-framework
          v-clickoutside="handleClickoutside(addCol)"
          :component-data="componentData"
          @drag-col-start="handleDragNewCol"
        />
      </div>
    </transition>
    <el-dialog
      class="edit-row-dialog"
      title="修改布局配置"
      :visible.sync="visiableDialog"
      append-to-body
      width="600px"
    >
      <el-form v-model="curRow" :inline="true" label-width="100px" label-position="left">
        <el-form-item label="布局高度(px)">
          <el-input v-model.number="curRow.height" />
        </el-form-item>
      </el-form>
      <div class="editor-box">
        <div>
          <div class="editor-inputs-box">
            <div v-for="(ipt, iptIndex) in curRow.cols" :key="iptIndex" class="input-item-box">
              <el-input
                v-model.number="ipt.value"
                size="mini"
                :maxlength="3"
                :minlength="1"
                :max="24"
                :min="1"
              />
            </div>
            <div class="controller-btn">
              <i class="el-icon-remove" title="remove-layout" @click="handleRemove" />
              <i class="el-icon-circle-plus" title="add-layout" @click="handleAdd" />
            </div>
          </div>
        </div>
      </div>
      <div class="layout-preview-box">
        <div
          v-for="(ipt, iptIndex) in curRow.cols"
          :key="iptIndex"
          class="preview-item"
          :style="previewColStyle({ width: ipt.value, height: 300 })"
        >{{ ipt.value }}</div>
      </div>
      <el-footer style="margin-top:30px;padding:0px">
        <el-button type="primary" style="float:right;" @click="confirmHandleEditRow">确认</el-button>
        <el-button
          type="default"
          style="float:right;margin-right:10px;"
          @click="visiableDialog = false"
        >取消</el-button>
      </el-footer>
    </el-dialog>
  </div>
</template>

<script>
import {
  deepClone,
  diffIndex,
  mixinObjs
} from './utils/index.js'
import {
  getInitRow,
  getInitCol,
  resetIndex,
  alignType
} from './utils/dragReport.js'
import colStyle from './mixins/methods/col-style'
import clickoutside from './directive/clickoutside'
import defaultFramework from './default-framework'
import defaultLayoutEditor from './default-layout-editor'
// import news from '@/modules/system/view/porlet/news'
// import userFavorite from '@/modules/system/view/porlet/userFavorite'
// import notice from '@/modules/system/view/porlet/notice'
import portletList from './portletList'
const colSkipArr = ['initCol']

export default {
  name: 'portal-edit',
  components: { defaultFramework, defaultLayoutEditor, ...portletList },
  directives: { clickoutside },
  mixins: [colStyle],
  props: {
    dragReportData: {
      type: Object,
      default: () => {
        return {
          title: '',
          children: []
        }
      }
    },
    componentData: {
      type: Array,
      default: () => {
        return []
      }
    }
  },
  data() {
    return {
      // 拖动 row 和 col 的内容存储地
      dragData: {
        // 拖动的如果是 row
        isRow: false,
        // 拖动的是新的 row
        isNewRow: false,
        // 拖动的是新的 col
        isNewCol: false,
        // col 信息
        col: null,
        // row 信息
        row: null
      },
      alignType,
      addContainerTop: -60,
      addRow: {
        show: false,
        showControllerBar: false
      },
      addCol: {
        show: false,
        showControllerBar: false
      },
      // 布局配置页面
      visiableDialog: false,
      curRow: {
        index: 0,
        height: 300,
        cols: [
          { height: 300, value: 24 }
        ]
      }
    }
  },
  computed: {
    floatBox() {
      return { top: `${this.addContainerTop}px` }
    }
  },
  watch: {
    'curRow.height': function (val) {
      this.curRow.cols.forEach(input => { input.height = val })
    }
  },
  mounted() {
    this.addListener()
  },
  beforeDestroy() {
    window.removeEventListener('scroll', this.$$listeners.scroll)
  },
  methods: {
    handleRemove() {
      if (this.curRow.cols.length === 1) {
        this.$message.warning('至少需要一列布局')
        return
      }
      this.curRow.cols.splice(this.curRow.cols.length - 1, 1)
    },
    handleAdd() {
      if (this.curRow.cols.length === 24) {
        this.$message.warning('至多只能有二十四列布局')
        return
      }
      this.curRow.cols.push({ value: 0, height: this.curRow.height })
    },
    // edit row functions
    // 拖动新的 row
    handleDragNewRow(event, row) {
      this.dragData.isRow = true
      this.dragData.isNewRow = true
      this.dragData.row = getInitRow(row)
    },
    // 拖动已存在的 row 重排时
    handleDragRow(event, row) {
      this.dragData.isRow = true
      this.dragData.isNewRow = false
      this.dragData.row = row
    },
    // 对 dropRow 的函数处理
    handleDropRow(event, drapRow) {
      if (!this.dragData.isRow) return
      const { row: dragRow } = this.dragData
      const { children: rows } = this.dragReportData
      // 用来限制高度
      // let sum = rows.reduce((pre, curr) => (pre += curr.height), 0)
      if (!this.dragData.isNewRow) {
        // 如果拖拽的不是新的 row
        // 则交换两个 row 的 index，并对 rows 进行 sort
        [dragRow.index, drapRow.index] = [drapRow.index, dragRow.index]
        this.sortRows()
      } else {
        // 如果拖拽的是新的 row
        // 用来限制高度
        // if (sum + dragRow.initHeight > 2300)  this.$message("1_高度超出一页纸")
        // 找出 drapRow 后面的所有 rows，并把他们的 index + 1
        // 为的是拖拽放置的时候能放置在被 drap 的 row 后面
        rows.forEach(row => (row.index > drapRow.index ? row.index++ : null))
        rows.push(mixinObjs(dragRow, { index: drapRow.index + 1 }))
        this.sortRows()
      }
    },
    // 重排 rows，并会对 index 重新赋值
    sortRows() {
      const { children: rows } = this.dragReportData
      rows.sort(diffIndex)
      rows.forEach(resetIndex)
    },
    // 删除某 row
    handleRemoveRow(event, row) {
      const { children: rows } = this.dragReportData
      if (rows.length === 1) {
        this.$message.warning('至少需要一行布局')
        return
      }
      rows.splice(row.index - 1, 1)
      this.sortRows()
    },
    handleEditRow(event, row) {
      this.visiableDialog = true
      this.curRow.index = row.index
      this.curRow.height = row.initHeight
      this.curRow.cols = []
      row.children.forEach(col => {
        this.curRow.cols.push({
          height: row.initHeight,
          value: col.initCol
        })
      })
    },
    confirmHandleEditRow() {
      // 重新给当前行规划布局
      const currentRow = this.dragReportData.children.find(row => row.index === this.curRow.index)
      currentRow.initHeight = this.curRow.height
      const min = Math.min(currentRow.children.length, this.curRow.cols.length)
      currentRow.children = currentRow.children.slice(0, min)
      this.curRow.cols.forEach((col, index) => {
        const curCol = currentRow.children[index]
        if (curCol) {
          curCol.initCol = col.value
        } else {
          currentRow.children.push({
            code: null,
            name: null,
            col: col.value,
            initCol: col.value,
            showChildrenControllerBar: false
          })
        }
      })
      this.visiableDialog = false
    },
    // edit col functions
    handleDragOver(event) {
      // 默认情况下，对于 drop 的元素，要使用 dragover 移除默认事件，event.preventDefault()
      event.preventDefault()
    },
    // 拖动一个新的 col
    handleDragNewCol(event, col) {
      this.dragData.isRow = false
      this.dragData.isNewCol = true
      this.dragData.col = col
      // 把布局盒子隐藏，方便排版
      this.addCol.show = false
    },
    // 拖动一个已存在布局中的 col
    handleDragCol(event, col) {
      this.dragData.isRow = false
      this.dragData.isNewCol = false
      this.dragData.col = col
    },
    // 放置一个 col
    handleDropCol(event, col) {
      // 如果拖动的是 row，不用管
      if (this.dragData.isRow) return
      const { col: dragCol } = this.dragData
      const cacheDragCol = deepClone(dragCol)
      const cacheCol = deepClone(col)
      if (!this.dragData.isNewCol) {
        // 若拖动的 col 不是新 col
        // 有两种情况要考虑，一个是放置的位置没有 col
        // 一个是放置的位置有 col
        // TODO 最好不是用 previewImage 来判断，想办法用其他办法来判断
        if (col.code) {
          // 若放置的位置不是空的，则将两者交换
          this.setCol(cacheDragCol, col)
          this.setCol(cacheCol, dragCol)
        } else {
          // 若放置的位置是空的，则将 col 赋值并重置 from
          this.setCol(dragCol, col)
          this.resetCol(dragCol)
        }
      } else {
        // 若拖动的 col 是新的 col
        // 则只需要将 col 赋值即可
        this.setCol(cacheDragCol, col)
        this.addCol.show = true
      }
    },
    delCol(col) {
      for (const key in col) {
        if (col.hasOwnProperty(key)) {
          if (colSkipArr.indexOf(key) === -1) {
            this.$delete(col, key)
          }
        }
      }
    },
    setCol(from, to) {
      for (const key in from) {
        if (from.hasOwnProperty(key)) {
          if (colSkipArr.indexOf(key) === -1) {
            this.$set(to, key, from[key])
          }
        }
      }
    },
    showEditDialog(col) {
      this.$set(col, 'showEditTitle', !col.showEditTitle)
    },
    showSettingDialog(col) {
      this.$set(col, 'dialogVisible', true)
    },
    resetCol(col) {
      const init = getInitCol({
        initCol: col.initCol
      })
      this.delCol(col)
      this.setCol(init, col)
    },
    // other function
    rowStyle(row) {
      return { justifyContent: row.align, height: `${row.initHeight}px` }
    },
    handleClickoutside(container) {
      return function () {
        container.show && (container.show = false)
      }
    },
    handleListenerScroll() {
      const scrollTop =
        this.$('.app-main')[0].scrollTop ||
        window.pageYOffset ||
        document.body.scrollTop
      this.addContainerTop = scrollTop - 60
    },
    handleDialogListenerScroll() {
      const scrollTop =
        this.$('.report-container').closest('div[role=\'dialog\']')[0].scrollTop ||
        window.pageYOffset ||
        document.body.scrollTop
      this.addContainerTop = scrollTop - 60
    },
    addListener() {
      this.$$listeners = { scroll: null }
      const dialog = this.$('.report-container').closest('div[role=\'dialog\']')
      if (dialog && dialog.length > 0) {
        // 弹框模式的滚动监听
        this.$$listeners.scroll = this._.debounce(this.handleDialogListenerScroll, 10)
        dialog[0].addEventListener('scroll', this.$$listeners.scroll)
      } else {
        // 内嵌模式的滚动监听
        this.$$listeners.scroll = this._.debounce(this.handleListenerScroll, 10)
        this.$('.app-main')[0].addEventListener('scroll', this.$$listeners.scroll)
      }
    }
  }
}
</script>
<style lang="scss" >
@import "./styles/global.scss";
</style>
<style lang="scss" scoped>
@import "./layout.scss";
@import "./styles/variable.scss";
.edit-row-dialog {
  @include default-flex;
  flex-wrap: wrap;
  flex-flow: column;
  height: 100%;
  padding: 2rem 0;
  & .editor-box {
    @include default-flex;
    @include flex-full;
    flex-wrap: wrap;
    height: 80px;
    & .editor-inputs-box {
      margin-top: 5px;
      @include default-flex;
      @include flex-full;
      flex-wrap: wrap;
      & .input-item-box {
        width: 50px;
        margin-right: 5px;
        margin-top: 5px;
      }
      & .controller-btn {
        font-size: 1.8rem;
        margin-top: 5px;
        & i {
          cursor: pointer;
        }
      }
    }
  }
  & .layout-preview-box {
    @include default-flex;
    @include flex-full;
    & .preview-item {
      @include default-col-style;
      @include default-col-layout;
    }
  }
}
</style>

